<template>
  <div class="table">
    <div class="operation-bar">
      <slot name="operation-default"></slot>
      <div
        v-if="props.http.batchDel"
        v-permission="props.httpPermission?.batchDel"
        class="item"
      >
        <a-button
          :disabled="$selectedKeys.length <= 0"
          type="outline"
          status="danger"
          @click="openDel($selectedKeys)"
          >删除</a-button
        ></div
      >

      <div
        v-if="props.http.empty"
        v-permission="props.httpPermission?.empty"
        class="item"
      >
        <a-button type="outline" status="warning" @click="openEmpty"
          >清空</a-button
        ></div
      >
      <div v-if="props.importConfig" class="item">
        <a-button
          v-permission="props.importConfig?.permission"
          style="
            color: rgb(var(--primary-4));
            border-color: rgb(var(--primary-4));
          "
          type="outline"
          status="normal"
          @click="imported"
          >导入</a-button
        ></div
      >
      <div v-if="props.http.exported" class="item">
        <a-button
          v-permission="props.httpPermission?.exported"
          style="
            color: rgb(var(--warning-4));
            border-color: rgb(var(--warning-4));
          "
          type="outline"
          status="normal"
          :loading="exportLoading"
          @click="exported"
          >导出</a-button
        ></div
      >
      <div
        v-if="props.http.closed"
        v-permission="props.httpPermission?.closed"
        class="item"
      >
        <a-button
          style="
            color: rgb(var(--warning-7));
            border-color: rgb(var(--warning-7));
          "
          type="outline"
          status="warning"
          @click="props.http.closed"
          >关闭</a-button
        ></div
      >
    </div>
    <div v-if="columns.length > 0" class="table">
      <a-table
        v-model:selectedKeys="$selectedKeys"
        :row-key="tableRowKey"
        :columns="columns"
        :data="data"
        :pagination="pagination"
        :row-selection="rowSelection"
        :loading="loading"
        :scroll="scroll"
        @page-change="pageChange"
        @page-size-change="pageSizeChange"
        @selection-change="selectionChange"
      >
        <template #expand-icon="{ expanded, record }">
          <template v-if="record.children.length > 0">
            <icon-right v-if="!expanded" />
            <icon-down v-else />
          </template>
        </template>
        <template v-for="item in slotColumn" :key="item" #[item]="{ record }">
          <slot
            v-if="item !== 'optional'"
            :name="item"
            v-bind="{
              row: record,
              column: getColumn(item),
            }"
          >
            <span>{{ record[item] }}</span>
          </slot>
          <template v-else>
            <slot
              :name="item"
              v-bind="{ row: record, column: getColumn(item) }"
            >
            </slot>
            <a-button
              v-if="props.http.del"
              v-permission="props.httpPermission?.del"
              type="text"
              status="danger"
              @click="openDel(record[rowKey])"
              >删除</a-button
            >
            <template v-if="slots.more">
              <a-dropdown
                v-permission="props.httpPermission?.more"
                position="bl"
              >
                <a-button
                  style="color: rgb(var(--primary-7))"
                  type="text"
                  status="success"
                  >更多</a-button
                >
                <template #content>
                  <slot
                    name="more"
                    v-bind="{ row: record, column: getColumn(item) }"
                  ></slot>
                </template>
              </a-dropdown>
            </template>
          </template>
        </template>
      </a-table>
    </div>
    <delModal
      v-model:visible="delVisible"
      modal-title="系统提示"
      :msg="delMsg"
      :type="delType"
      @modal-ok="delModalOk"
    ></delModal>
    <ImportBox
      ref="importBox"
      v-model:refresh="$refresh"
      :import-config="importConfig"
    ></ImportBox>
  </div>
</template>

<script lang="ts" setup>
  import {
    ref,
    reactive,
    PropType,
    computed,
    watch,
    toRaw,
    useSlots,
  } from 'vue';
  import type {
    TableData,
    TableColumnData,
  } from '@arco-design/web-vue/es/table/interface';
  import { Message } from '@arco-design/web-vue';
  import delModal from './operation/del-modal.vue';

  // 定义 props
  const props = defineProps({
    columns: {
      type: Array as PropType<TableColumnData[]>,
      default() {
        return [];
      },
    },
    dataSource: {
      type: Array as PropType<TableData[]>,
      default() {
        return [];
      },
    },
    params: {
      type: Object,
      default() {
        return {};
      },
    },
    http: {
      type: Object,
      default: () => {
        return {
          list: null,
          del: null,
        };
      },
    },
    httpPermission: {
      type: Object,
      default: () => {
        return {
          list: null,
          del: null,
        };
      },
    },
    pagination: {
      type: [Object, Boolean],
      default() {
        return {
          hideOnSinglePage: false,
          simple: false,
        };
      },
    },
    refresh: {
      type: Boolean,
      default: false,
    },
    httpDataKey: {
      type: String,
      default: 'rows',
    },
    rowKey: {
      type: String,
      default: 'id',
    },
    formatData: {
      type: Function,
    },
    selectedKeys: {
      type: [Array, Boolean],
    },
    importConfig: {
      type: Object,
    },
    scroll: {
      type: Object,
    },
  });
  const importBox = ref();
  const $refresh = ref(false);
  const slots: { [x: string]: any } = toRaw(useSlots());
  // 定义 emit
  const emit = defineEmits(['update:refresh', 'update:selectedKeys']);
  //  定义分页
  const page = reactive({
    pageNum: 1,
    pageSize: 10,
  });
  // 定义行选择器
  const rowSelection: any = props.selectedKeys
    ? {
        type: 'checkbox',
        showCheckedAll: true,
        fixed: true,
      }
    : null;
  // 内部选中行
  const $selectedKeys = ref([]);
  // 选中行改变
  const selectionChange = (e: any) => {
    // eslint-disable-next-line no-console
    emit('update:selectedKeys', e);
  };
  const delMsg = ref('');
  const delType = ref('del');
  // 定义删除开关
  const delVisible = ref(false);
  const exportLoading = ref(false);

  // 定义数据
  const data = ref<any[]>([]);
  // 定义数据总量
  const dataCount = ref(0);
  // 定义表格加载
  const loading = ref(false);
  // 定义删除数据 ID
  const delIds = ref([]);
  // 定义在线获取数据方法
  const getHttpData = async () => {
    if (props.http.list && props.refresh) {
      loading.value = true;
      const res = await props.http.list({
        ...page,
        ...props.params,
      });
      const { code, total, msg } = res;
      loading.value = false;
      $selectedKeys.value = [];
      emit('update:refresh', false);
      emit('update:selectedKeys', []);
      if (code !== 200) {
        Message.error(msg);
        return;
      }
      if (props.formatData) {
        data.value = props.formatData([...res[props.httpDataKey]]);
      } else {
        data.value = [...res[props.httpDataKey]];
        dataCount.value = total;
      }
    }
  };
  const getPageData = () => {
    data.value = props.dataSource;
    dataCount.value = props.dataSource.length;
  };
  // 定义 refresh 监听器 用于数据刷新
  watch(
    () => props.refresh,
    (val) => {
      if (val === true) {
        getHttpData();
        // emit('update:refresh', false);
      } else {
        $refresh.value = false;
      }
    },
    {
      deep: true,
      immediate: true,
    }
  );
  watch(
    () => props.dataSource,
    () => {
      getPageData();
    },
    {
      deep: true,
      immediate: true,
    }
  );
  watch(
    () => $refresh,
    (val: any) => {
      if (val.value === true) {
        emit('update:refresh', true);
      }
    },
    {
      deep: true,
      immediate: true,
    }
  );
  // 定义分页 计算属性
  const pagination = computed(() => {
    if (!props.pagination) {
      return false;
    }
    const temp = props.pagination as any;
    return {
      'total': dataCount.value || 0,
      'current': page.pageNum || 1,
      'page-size': page.pageSize || 10,
      'hide-on-single-page': temp?.hideOnSinglePage || false,
      'simple': temp?.simple || false,
    };
  });
  const slotColumn = computed(() => {
    const slotList: Array<TableColumnData> = props.columns;
    if (slotList.length <= 0) return [];
    return slotList
      .filter((item) => item.slotName)
      .map((item) => item.slotName) as any;
  });
  const tableRowKey = computed(() => {
    return props.rowKey ?? 'id';
  });
  const getColumn = computed(() => {
    // eslint-disable-next-line func-names
    return function (item: any) {
      return props.columns.find((column) => column.slotName === item) || {};
    };
  });

  // 定义分页页码变化方法
  const pageChange = async (e: number) => {
    emit('update:refresh', true);
    page.pageNum = e;
    if (props.http.list) {
      getHttpData();
    }
  };
  // 定义分页页大小变化方法
  const pageSizeChange = async (e: number) => {
    emit('update:refresh', true);
    page.pageSize = e;
    if (props.http.list) {
      getHttpData();
    }
  };
  // 初始化
  const initData = () => {
    if (props.http.list) {
      getHttpData();
    } else {
      getPageData();
      // 本地数据渲染
    }
  };
  initData();
  // 操作方法
  const openDel = async (ids: any) => {
    delVisible.value = true;
    delType.value = 'del';
    if (Array.isArray(ids)) {
      delType.value = 'batchDel';
      delIds.value = ids.join(',') as any;
    } else {
      delIds.value = ids;
    }
    delMsg.value = `是否确认删除为"${delIds.value}"的数据项？`;
  };
  // 删除确认
  const delModalOk = async ({ type, ck }: { type: string; ck: any }) => {
    if (type === 'del' || type === 'batchDel') {
      let http = null;
      if (type === 'batchDel') {
        if (!props.http.batchDel) {
          throw new Error('xTable 没有数据删除方法');
        } else {
          http = props.http.batchDel;
        }
      } else if (!props.http.del) {
        throw new Error('xTable 没有数据删除方法');
      } else {
        http = props.http.del;
      }

      const { code, msg } = await http(delIds.value);
      if (code !== 200) {
        Message.error(msg);
      }
      delVisible.value = false;
      ck({ closed: true });
      delIds.value = [];
      emit('update:refresh', true);
      // getHttpData();
    } else if (type === 'empty') {
      if (!props.http.empty) {
        throw new Error('xTable 没有数据清空方法');
      }
      const { code, msg } = await props.http.empty(
        $selectedKeys.value.join(',')
      );
      if (code !== 200) {
        Message.error(msg);
      }
      delVisible.value = false;
      ck({ closed: true });
      emit('update:refresh', true);
      // getHttpData();
    }
  };
  // 打开清空
  const openEmpty = async () => {
    delVisible.value = true;
    delType.value = 'empty';
    delMsg.value = `是否确认清空所有数据项？`;
  };
  const exported = () => {
    if (!props.http.exported) {
      throw new Error('xTable 没有数据导出方法');
    }
    props.http.exported(
      {
        ...page,
        ...props.params,
      },
      (eloading: boolean) => {
        exportLoading.value = eloading;
      }
    );
  };
  const imported = () => {
    importBox.value.open();
  };
</script>

<style lang="less" scoped>
  :deep(.arco-table .arco-table-expand-btn) {
    background-color: transparent;
  }
  :deep(.arco-table .arco-table-expand-btn:hover) {
    background-color: transparent;
  }
</style>

<style lang="less">
  .table {
    .operation-bar {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      .item {
        margin-left: 8px;
        margin-bottom: 20px;
      }
    }
  }
</style>
